"""
任务相关数据模型

定义处理任务和工作流相关的数据模型。
"""

from datetime import datetime
from typing import Dict, Any, Optional, List
from enum import Enum
import json

from sqlalchemy import Column, Integer, String, Float, Text, Boolean, ForeignKey, Enum as SQLEnum, Index, DateTime
from sqlalchemy.orm import relationship

from .base import BaseModel, JSONField


class TaskStatus(Enum):
    """任务状态枚举"""
    PENDING = "pending"          # 等待中
    RUNNING = "running"          # 运行中
    COMPLETED = "completed"      # 已完成
    FAILED = "failed"           # 失败
    CANCELLED = "cancelled"      # 已取消
    PAUSED = "paused"           # 已暂停


class TaskType(Enum):
    """任务类型枚举"""
    SCAN = "scan"                       # 目录扫描
    METADATA_EXTRACTION = "metadata"    # 元数据提取
    CLASSIFICATION = "classification"   # 视频分类
    FRAME_EXTRACTION = "frames"         # 帧提取
    TRANSCODING = "transcoding"         # 转码
    THUMBNAIL = "thumbnail"             # 缩略图生成
    WORKFLOW = "workflow"               # 工作流执行
    EXPORT = "export"                   # 导出
    CLEANUP = "cleanup"                 # 清理


class ProcessingTask(BaseModel):
    """
    处理任务模型
    
    存储各种处理任务的信息和状态。
    """
    
    __tablename__ = 'processing_tasks'
    
    # 任务基本信息
    task_type = Column(SQLEnum(TaskType), nullable=False, index=True)
    task_name = Column(String(200), nullable=False)
    description = Column(Text, nullable=True)
    
    # 关联视频（可选）
    video_id = Column(Integer, ForeignKey('videos.id'), nullable=True)
    video = relationship("Video", back_populates="processing_tasks")
    
    # 任务状态
    status = Column(SQLEnum(TaskStatus), default=TaskStatus.PENDING, nullable=False, index=True)
    progress = Column(Float, default=0.0, nullable=False)  # 0.0-100.0
    
    # 时间信息
    started_at = Column(DateTime, nullable=True)
    completed_at = Column(DateTime, nullable=True)
    estimated_duration = Column(Float, nullable=True)  # 预估时长（秒）
    actual_duration = Column(Float, nullable=True)     # 实际时长（秒）
    
    # 任务配置和结果
    input_params = Column(Text, nullable=True)   # JSON格式的输入参数
    output_data = Column(Text, nullable=True)    # JSON格式的输出数据
    error_message = Column(Text, nullable=True)
    error_details = Column(Text, nullable=True)  # JSON格式的错误详情
    
    # 执行信息
    worker_id = Column(String(100), nullable=True)
    priority = Column(Integer, default=0, nullable=False)  # 优先级，数字越大优先级越高
    retry_count = Column(Integer, default=0, nullable=False)
    max_retries = Column(Integer, default=3, nullable=False)
    
    # 依赖关系
    parent_task_id = Column(Integer, ForeignKey('processing_tasks.id'), nullable=True)
    parent_task = relationship("ProcessingTask", remote_side="ProcessingTask.id", backref="child_tasks")
    
    # 索引
    __table_args__ = (
        Index('idx_task_status_type', 'status', 'task_type'),
        Index('idx_task_video_status', 'video_id', 'status'),
        Index('idx_task_priority_created', 'priority', 'created_at'),
    )
    
    def get_input_params_dict(self) -> Dict[str, Any]:
        """获取输入参数字典"""
        return JSONField.deserialize(self.input_params) or {}
    
    def set_input_params_dict(self, params: Dict[str, Any]) -> None:
        """设置输入参数字典"""
        self.input_params = JSONField.serialize(params)
    
    def get_output_data_dict(self) -> Dict[str, Any]:
        """获取输出数据字典"""
        return JSONField.deserialize(self.output_data) or {}
    
    def set_output_data_dict(self, data: Dict[str, Any]) -> None:
        """设置输出数据字典"""
        self.output_data = JSONField.serialize(data)
    
    def get_error_details_dict(self) -> Dict[str, Any]:
        """获取错误详情字典"""
        return JSONField.deserialize(self.error_details) or {}
    
    def set_error_details_dict(self, details: Dict[str, Any]) -> None:
        """设置错误详情字典"""
        self.error_details = JSONField.serialize(details)
    
    @property
    def is_running(self) -> bool:
        """是否正在运行"""
        return self.status == TaskStatus.RUNNING
    
    @property
    def is_completed(self) -> bool:
        """是否已完成"""
        return self.status == TaskStatus.COMPLETED
    
    @property
    def is_failed(self) -> bool:
        """是否失败"""
        return self.status == TaskStatus.FAILED
    
    @property
    def can_retry(self) -> bool:
        """是否可以重试"""
        return self.is_failed and self.retry_count < self.max_retries
    
    @property
    def duration_seconds(self) -> Optional[float]:
        """任务持续时间（秒）"""
        if self.started_at and self.completed_at:
            return (self.completed_at - self.started_at).total_seconds()
        elif self.started_at and self.is_running:
            return (datetime.utcnow() - self.started_at).total_seconds()
        return self.actual_duration
    
    def start(self, worker_id: str = None) -> None:
        """开始任务"""
        self.status = TaskStatus.RUNNING
        self.started_at = datetime.utcnow()
        self.worker_id = worker_id
        self.updated_at = datetime.utcnow()
    
    def complete(self, output_data: Dict[str, Any] = None) -> None:
        """完成任务"""
        self.status = TaskStatus.COMPLETED
        self.completed_at = datetime.utcnow()
        self.progress = 100.0
        
        if output_data:
            self.set_output_data_dict(output_data)
        
        if self.started_at:
            self.actual_duration = (self.completed_at - self.started_at).total_seconds()
        
        self.updated_at = datetime.utcnow()
    
    def fail(self, error_message: str, error_details: Dict[str, Any] = None) -> None:
        """任务失败"""
        self.status = TaskStatus.FAILED
        self.completed_at = datetime.utcnow()
        self.error_message = error_message
        
        if error_details:
            self.set_error_details_dict(error_details)
        
        if self.started_at:
            self.actual_duration = (self.completed_at - self.started_at).total_seconds()
        
        self.updated_at = datetime.utcnow()
    
    def cancel(self) -> None:
        """取消任务"""
        self.status = TaskStatus.CANCELLED
        self.completed_at = datetime.utcnow()
        
        if self.started_at:
            self.actual_duration = (self.completed_at - self.started_at).total_seconds()
        
        self.updated_at = datetime.utcnow()
    
    def pause(self) -> None:
        """暂停任务"""
        if self.is_running:
            self.status = TaskStatus.PAUSED
            self.updated_at = datetime.utcnow()
    
    def resume(self) -> None:
        """恢复任务"""
        if self.status == TaskStatus.PAUSED:
            self.status = TaskStatus.RUNNING
            self.updated_at = datetime.utcnow()
    
    def retry(self) -> None:
        """重试任务"""
        if self.can_retry:
            self.retry_count += 1
            self.status = TaskStatus.PENDING
            self.progress = 0.0
            self.started_at = None
            self.completed_at = None
            self.error_message = None
            self.error_details = None
            self.updated_at = datetime.utcnow()
    
    def update_progress(self, progress: float, message: str = None) -> None:
        """更新进度"""
        self.progress = max(0.0, min(100.0, progress))
        
        if message:
            # 可以将进度消息存储在输出数据中
            output_data = self.get_output_data_dict()
            output_data['progress_message'] = message
            self.set_output_data_dict(output_data)
        
        self.updated_at = datetime.utcnow()
    
    def to_dict(self, include_relationships: bool = False) -> Dict[str, Any]:
        """转换为字典"""
        result = super().to_dict(include_relationships)
        
        # 添加计算属性
        result.update({
            'input_params_dict': self.get_input_params_dict(),
            'output_data_dict': self.get_output_data_dict(),
            'error_details_dict': self.get_error_details_dict(),
            'is_running': self.is_running,
            'is_completed': self.is_completed,
            'is_failed': self.is_failed,
            'can_retry': self.can_retry,
            'duration_seconds': self.duration_seconds
        })
        
        # 转换枚举值
        result['task_type'] = self.task_type.value if self.task_type else None
        result['status'] = self.status.value if self.status else None
        
        return result
